<template>
    <div class="vue-flow-container">
        <!-- 左中右布局 -->
        <div class="flex gap-4">
            <div class="flex-none left-component w-1/6">
                <div class="flex flex-col gap-2">
                    <div class="grid grid-cols-2 gap-2">
                        <div v-for="component in components" :key="component.name"
                            class="flex-none truncate cursor-move h-14 bg-slate-100 rounded-md flex items-center justify-center"
                            draggable="true" @dragstart="onDragStart($event, component)">
                            {{ component.attributes.title }}
                        </div>
                    </div>
                </div>
            </div>
            <div class="grow h-[calc(100vh-145px)] bg-white rounded-md">
                <VueFlow ref="flow" v-model="elements" :default-zoom="1" :min-zoom="0.2" :max-zoom="4"
                    :node-types="nodeTypes" :fit-view="true" class="vue-flow" @dragover="onDragOver" @drop="onDrop"
                    @connect="onConnect">
                    <template v-for="(_, name) in nodeTypes" :key="name" #[`node-${name}`]="nodeProps">
                        <component :is="nodeTypes[name]" :data="nodeProps.data" :id="nodeProps.id"
                            @updateData="handleNodeDataUpdate" @attr="(data: any) => attr = data" />
                    </template>
                </VueFlow>
            </div>
            <div class="flex-none w-1/6 h-[calc(100vh-145px)] bg-white rounded-md p-4">
                {{ attr }}
            </div>
        </div>
    </div>
</template>

<script lang="ts" setup>
import { ref, computed } from 'vue'
import { VueFlow, useVueFlow } from '@vue-flow/core'
import type { Node, Edge, Connection } from '@vue-flow/core'
import { getComponentList, nodeTypes } from './components/index'
import '@vue-flow/core/dist/style.css'
import '@vue-flow/core/dist/theme-default.css'

const attr = ref()

// 更新 elements 的类型定义，使其能够同时容纳 Node 和 Edge 类型
const elements = ref<(Node | Edge)[]>([])
const flow = ref<any>(null)

interface FlowElement {
    id: string
    type: string
    position: { x: number; y: number }
    data: {
        [key: string]: any
    }
}

const components = computed(() => getComponentList())

// 拖拽开始
const onDragStart = (event: DragEvent, component: any) => {
    if (event.dataTransfer) {
        event.dataTransfer.setData('component', JSON.stringify(component))
    }
}

// 拖拽经过
const onDragOver = (event: DragEvent) => {
    event.preventDefault()
}

// 放置
const onDrop = (event: DragEvent) => {
    event.preventDefault()
    if (!event.dataTransfer) return
    const component = JSON.parse(event.dataTransfer.getData('component'))
    const position = flow.value.project({
        x: event.clientX,
        y: event.clientY
    })
    const newNode: Node = { // 使用 Node 类型
        id: `${component.name}-${Date.now()}`,
        type: component.name,
        position,
        data: {
            ...component.attributes.nodes.data
        }
    }
    elements.value = [...elements.value, newNode]
}

// 处理连线
const onConnect = (connection: Connection) => {
    const newEdge: Edge = { // 使用 Edge 类型
        id: `edge-${connection.source}-${connection.target}`,
        source: connection.source,
        target: connection.target,
        animated: true,
        style: { stroke: '#1976d2' }
    }
    elements.value = [...elements.value, newEdge]
}

// 处理节点数据更新事件 - 实现"最后一个更新的数据"逻辑
const handleNodeDataUpdate = ({ id, content }: { id: string, content: any }) => {
    // 找到发出事件的源节点所连接的所有目标节点
    const connectionsFromSource = elements.value.filter(el => 'source' in el && el.source === id) as Edge[]

    // 遍历所有以该源节点为起点的连线
    connectionsFromSource.forEach(connection => {
        // 找到目标节点
        const targetNodeIndex = elements.value.findIndex(el => el.id === connection.target)
        if (targetNodeIndex !== -1) {
            const targetNode = elements.value[targetNodeIndex] as Node

            // 直接用源节点最新的 content 覆盖目标节点的 content
            // 创建一个新的 data 对象以确保响应性
            targetNode.data = {
                ...targetNode.data,
                content: content
            }
        }
    })
}

</script>

<style scoped lang="scss">
.vue-flow-container {
    .left-component {
        padding: 10px;
        height: calc(100vh - 145px);
        background-color: white;
        border-radius: 0.375rem;
    }

    .vue-flow {
        width: 100%;
        height: 100%;
    }
}
</style>